/**
 *  @file MemReleasePool.h
 *
 *  This memory auto release pool is inspired from Objective-C.
 *  It has the following features:
 *  1) maintain reference count for each memory block
 *  2) freeing a pool will free all memory blocks attached to it
 *  3) an optional destructor function can be specified
 *  
 *  Important notes:
 *    -- memory blocks can now be safely allocated from one thread, then passed to another thread
 *       and released there, thanks to the global lock mechanism. All the following MRP_* functions
 *       are now thread safe (except MRP_GlobalInit and MRP_GlobalFinish, which have to be called
 *       in the main thread)
 *    -- since memory allocations/releases are now thread safe, functions like
 *           "MRP_UnlinkFromPool"
 *           "MRP_AddToPool"
 *           "MRP_AddToCurPool"
 *       are now quite useless (originally used to move memory blocks from thread to another).
 *       They are remained just in case some time in future their usage can be uncovered.
 *
 *  When using this memory pool, follow the 3 rules of the AutoReleasePool of Objective-C:
 *  1) If memory is allocated from "MRP_Calloc", maintain the memory yourself (i.e. call "MRP_Release"
 *     yourself). "MRP_CallocARel" will attach the memory block to the current auto release pool automatically.
 *  2) If a pointer is obtained from other functions, do nothing. However, if you want to get hold of
 *     an object, retain it and release it finally yourself.
 *  3) Balance the number of "Retain" and "Release".
 *
 *
 *  General usage:
 *  
 *  int main(void) 
 *  {
 *     // allocate a new pool
 *     memrelpool_t * pRelPool = MRP_CreateRelPool();
 *  
 *     // allocate memory which will be attached to the current pool automatically
 *     int * arrA = (int*)MRP_CallocARel(4, sizeof(int));
 *     int * arrB = (int*)MRP_CallocARel(3, sizeof(int));
 *
 *     // do some useful things here
 *
 *     // release the pool will also release memory blocks attached to it
 *     MRP_FreePool(pRelPool);
 *
 *     return 0;
 *  }
 */

#ifndef _MEMRELEASEPOOL_H_
#define _MEMRELEASEPOOL_H_

#include "commontypes.h"

#ifdef __cplusplus
extern "C" {
#endif

//! memory pool forward declaration
typedef struct _memrelpool memrelpool_t;

//! Destructor function
typedef void (*dtorfunc_t)(void*);

//! Call this first in the main thread of a program before using any of the following functions
_DLLAPI bool_t MRP_GlobalInit(void);
/**
 *  Call this before 'main' function returns
 *
 *  @note this *WON'T* clean up any memory pool for you 
 */
_DLLAPI bool_t MRP_GlobalFinish(void);


_DLLAPI memrelpool_t * MRP_CreateRelPool(void);
_DLLAPI void MRP_FreePool(memrelpool_t * pRelPool);
_DLLAPI bool_t MRP_UnlinkPoolFromGroup(memrelpool_t * pRelPool);
_DLLAPI bool_t MRP_AddPoolAsCurrentPool(memrelpool_t * pRelPool);
_DLLAPI int MRP_GetPoolNodesCount(memrelpool_t * pRelPool);
_DLLAPI int MRP_GetPoolsCount(void);
#ifdef _DEBUG
_DLLAPI int MRP_GetDebugPoolNodesCount(void);
#endif

_DLLAPI int MRP_Release(void * pMemLoc);
_DLLAPI int MRP_Retain(void * pMemLoc);
_DLLAPI void *MRP_UnlinkFromPool(void * pMemLoc);
_DLLAPI bool_t MRP_AddToPool(void * pMemLoc, memrelpool_t *pRelPool);
_DLLAPI bool_t MRP_AddToCurPool(void * pMemLoc);
_DLLAPI bool_t MRP_AddToDefaultPool(void * pMemLoc);

_DLLAPI void * MRP_Calloc(sz_t num, sz_t size);
_DLLAPI void * MRP_CallocDtor(sz_t num, sz_t size, dtorfunc_t dtorFunc);
_DLLAPI void * MRP_CallocARel(sz_t num, sz_t size);
_DLLAPI void * MRP_CallocARelDtor(sz_t num, sz_t size, dtorfunc_t dtorFunc);
_DLLAPI void * MRP_Realloc(void * pMemLoc, sz_t size);

_DLLAPI int MRP_AssignWeakRefToken(void * pMemLoc);
_DLLAPI bool_t MRP_IsWeakRefTokenEqual(void * pMemLoc, int token);

#ifdef __cplusplus
}
#endif

#endif
